
package com.openwater.tools;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

import android.content.res.Resources;
import android.opengl.GLES20;
import android.util.Log;

/**
 * @author fuxp
 * @date 2012-6-8
 * @version 1.0 Copyright Corporation 2013,fuxp, All Rights Reserved
 * @since
 */
public class ShaderUtil {

    private static final String TAG = ShaderUtil.class.toString();

    /**
     * create the shader program with vertex and fragment source
     * 
     * @param vertexSource vertex script source
     * @param fragmentSource source fragment script
     * @return shaderProgram the shader program uniform id in the GPU
     */
    public static int createProgram(String vertexSource, String fragmentSource) {
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0) {
            return 0;
        }
        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
        if (pixelShader == 0) {
            return 0;
        }
        int program = GLES20.glCreateProgram();
        if (program != 0) {
            GLES20.glAttachShader(program, vertexShader);
            checkGlError("glAttachShader");
            GLES20.glAttachShader(program, pixelShader);
            checkGlError("glAttachShader");
            GLES20.glLinkProgram(program);
            int[] linkStatus = new int[1];
            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
            if (linkStatus[0] != GLES20.GL_TRUE) {
                Log.e(TAG, "Could not link program: " + GLES20.glGetProgramInfoLog(program));
                GLES20.glDeleteProgram(program);
                program = 0;
            }
            Log.e(TAG, "program id is :" + program);
        }
        return program;
    }

    /**
     * load script and compile it
     * 
     * @param shaderType the type of the script ,it must one of the
     *            GLES20.GL_VERTEX_SHADER or GLES20.GL_FRATMENT_SHADER
     * @param source the source of the script
     * @return the id of shader in the GUP
     */
    private static int loadShader(int shaderType, String source) {
        int shader = GLES20.glCreateShader(shaderType);
        if (shader != 0) {
            GLES20.glShaderSource(shader, source);
            GLES20.glCompileShader(shader);
            int[] compiled = new int[1];
            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
            if (compiled[0] == 0) {
                Log.e(TAG, "Could not compile shader " + shaderType + ":");
                Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
                GLES20.glDeleteShader(shader);
                shader = 0;
            }
        }
        return shader;
    }

    /**
     * check if has error in the step
     * 
     * @param op
     */
    public static void checkGlError(String op) {
        int error;
        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            Log.e(TAG, op + ": glError " + error);
            throw new RuntimeException(op + ": glError " + error);
        }
    }

    /**
     * @param programId
     * @return true if already a shader program id
     */
    public boolean isProgram(int programId) {
        return GLES20.glIsProgram(programId);
    }

    /**
     * read source form the assets
     * 
     * @param fname file name
     * @param r resource reference
     * @return the script string
     */
    public static String getScriptFromAssets(Resources r, String fname) {
        String result = null;
        try {
            final InputStream in = r.getAssets().open(fname);
            int ch = 0;
            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
            while ((ch = in.read()) != -1) {
                baos.write(ch);
            }
            final byte[] buff = baos.toByteArray();
            baos.close();
            in.close();
            result = new String(buff, "UTF-8");
            result = result.replaceAll("\\r\\n", "\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    // public static String getScriptFromSrc(String fname) {
    //
    // URL url = ClassLoader.getSystemResource(fname);
    // String result = null;
    // if (url != null) {
    // Log.d(TAG, fname + ":" + url.toString());
    // try {
    // FileInputStream in = new FileInputStream(new File(url.toURI()));
    // int ch = 0;
    // final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    // while ((ch = in.read()) != -1) {
    // baos.write(ch);
    // }
    // final byte[] buff = baos.toByteArray();
    // baos.close();
    // in.close();
    // result = new String(buff, "UTF-8");
    // result = result.replaceAll("\\r\\n", "\n");
    // } catch (Exception e) {
    // e.printStackTrace();
    // }
    // }
    // return result;
    //
    // }
}
